package com.yuncheng.common.utils;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelCollection;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.export.ExcelExportService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yuncheng.common.base.entity.CcBaseEntity;
import com.yuncheng.constant.CommonConstant;
import com.yuncheng.i18n.ExcelI18n;
import com.yuncheng.utils.I18nUtil;
import com.yuncheng.utils.SpringContextUtils;
import com.yuncheng.utils.YmlConfigHelper;
import com.yuncheng.vo.HttpResult;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.stream.Collectors;

/**
 * excel导入导出工具类，对easypoi进一步封装
 * xiangda add 20201122
 */
public class CcExcelUtil {

    private static final Logger log = LoggerFactory.getLogger(CcExcelUtil.class);

    public static HttpResult<?> imporReturnRes(List<?> totalList, List<String> errorMessage) throws IOException {
        int errorLines = errorMessage.size();
        int successLines = totalList.size() - errorLines;
        if (errorLines == 0) {
            return HttpResult.ok(I18nUtil.message("import.sucess.tips",successLines));
        } else {
            JSONObject result = new JSONObject(5);
            int totalCount = successLines + errorLines;
            result.put("totalCount", totalCount);
            result.put("errorCount", errorLines);
            result.put("successCount", successLines);
            result.put("msg",I18nUtil.message("import.error.result",totalCount,successLines,errorLines));
            String fileUrl = saveErrorTxtByList(errorMessage, "userImportExcelErrorLog");
            int lastIndex = fileUrl.lastIndexOf(File.separator);
            String fileName = fileUrl.substring(lastIndex + 1);
            result.put("fileUrl", CommonConstant.PREFIX_SYSTEM + "/common/static/" + fileUrl);
            result.put("fileName", fileName);
            HttpResult res = HttpResult.ok(result);
            res.setCode(201);
            res.setMessage(I18nUtil.message("import.error.message"));
            return res;
        }
    }

    public static String saveErrorTxtByList(List<String> msg, String name) {
        String saveDir = "logs" + File.separator + DateUtils.nowStrTime(DateUtils.DATE_FORMAT_DAY) + File.separator;
        String saveFullDir = YmlConfigHelper.getUpload() + File.separator + saveDir;

        File saveFile = new File(saveFullDir);
        if (!saveFile.exists()) {
            saveFile.mkdirs();
        }
        name += DateUtils.nowStrTime(DateUtils.YYYYMMDDHHMMSS) + Math.round(Math.random() * 10000);
        String saveFilePath = saveFullDir + name + ".txt";
        try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(saveFilePath));
            for (String s : msg) {
                if (s.indexOf("_") > 0) {
                    String arr[] = s.split("_");
                    bw.write(I18nUtil.message("import.error.check",arr[0],s.substring(arr[0].length() + 1)));
                } else {
                    bw.write(s);
                }
                bw.write("\r\n");
            }
            bw.flush();
            bw.close();
        } catch (Exception e) {
            log.info("excel导入生成错误日志文件异常:" + e.getMessage());
        }
        return saveDir + name + ".txt";
    }

    public static List<String> saveListIntoDb(List<?> list, Class serviceClass, List<String> errorMessage) {
        IService bean = (IService) SpringContextUtils.getBean(serviceClass);
        for (int i = 0; i < list.size(); i++) {
            try {
                boolean save = bean.save(list.get(i));
                if (!save) {
                    throw new Exception(I18nUtil.message("import.save.error"));
                }
            } catch (Exception e) {
                int lineNumber = i + 1;
                errorMessage.add(I18nUtil.message("import.save.row.error",lineNumber,e.getMessage()));
                log.error(e.getMessage(), e);
            }
        }
        return errorMessage;
    }

    public static String saveBeanIntoDb(Object obj, Class serviceClass) {
        String message = "ok";
        IService bean = (IService) SpringContextUtils.getBean(serviceClass);
        try {
            boolean save = bean.save(obj);
            if (!save) {
                message = I18nUtil.message("import.save.error");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            message = I18nUtil.message("import.save.error");
        }
        return message;
    }

//    /**
//     * excel导入数据库通用方法，适用于没有特殊计算的excel导入
//     */
//    public static HttpResult<?> importExcel(Map<String, MultipartFile> fileMap, Class beanClass, Class serviceClass)throws IOException {
//        List<String> errorMessage = new ArrayList<>();
//        int successLines = 0, errorLines = 0;
//        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
//            MultipartFile file = entity.getValue();
//            ImportParams params = new ImportParams();
//            params.setTitleRows(1);
//            params.setNeedSave(true);
//            try {
//                List<Object>  listSysPositions = ExcelImportUtil.importExcel(file.getInputStream(), beanClass, params);
//                List<String> list = saveListIntoDb(listSysPositions, serviceClass, errorMessage);
//                errorLines+=list.size();
//                successLines+=(listSysPositions.size()-errorLines);
//            } catch (Exception e) {
//                log.error(e.getMessage(), e);
//                return HttpResult.error("文件导入失败:" + e.getMessage());
//            } finally {
//                try {
//                    file.getInputStream().close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//        return imporReturnRes(errorLines,successLines,errorMessage);
//    }

    /**
     * excel列表数据转换成JavaBean集合
     */
    public static <T> List<T> excelRecord2JavaList(HttpServletRequest request, Class<?> pojoClass, ImportParams params) throws IOException {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        Set<Map.Entry<String, MultipartFile>> fileSet = fileMap.entrySet();
        if (fileSet == null || fileSet.size() == 0) {
            return null;
        }
        Map.Entry<String, MultipartFile> entryMap = fileSet.iterator().next();
        MultipartFile file = entryMap.getValue();
        if (params == null) {
            params = new ImportParams();
            params.setTitleRows(1);
            params.setHeadRows(1);
            params.setNeedSave(true);
        }
        try {
            return ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        } finally {
            try {
                file.getInputStream().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * excel导入数据库通用方法
     */
    public static HttpResult<?> javaList2Db(List<?> beanList, Class<?> serviceClass) throws IOException {
        if (beanList == null || beanList.size() == 0) {
            return HttpResult.error(I18nUtil.message("excel.import.error"));
        }
        List<String> errorMessage = new ArrayList<>();
        //int successLines = 0, errorLines = 0;
        try {
            saveListIntoDb(beanList, serviceClass, errorMessage);
            // errorLines+=list.size();
            //successLines+=(beanList.size()-errorLines);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return HttpResult.error(I18nUtil.message("excel.import.error"));
        }
        return imporReturnRes(beanList, errorMessage);
    }


//    /**
//     * excel导出通用方法，适用于没有特殊计算的excel导入
//     */
//    public static ModelAndView exportExcel(List<? extends BaseEntity> pageList, String selections) {
//        ModelAndView mv = new ModelAndView(new EasypoiSingleExcelView());
//        //如果是页面选择记录，则导出当前选中的记录，否则导出满足查询条件的全部记录
//        List<?> exportList = pageList;
//        if(!StringUtils.isEmpty(selections)){
//            List<String> selectedList = Arrays.asList(selections.split(","));
//            exportList = pageList.stream().filter(item -> selectedList.contains(item.getId())).collect(Collectors.toList());
//        }
//        mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
//        return mv;
//    }

    /**
     * excel导出通用方法，适用于没有特殊计算的excel导入
     */
    public static <T> List<T> exportExcel(List<? extends CcBaseEntity> pageList, String selections) {
        //如果是页面选择记录，则导出当前选中的记录，否则导出满足查询条件的全部记录
        List exportList = pageList;
        if (!StringUtils.isEmpty(selections)) {
            List<String> selectedList = Arrays.asList(selections.split(","));
            exportList = pageList.stream().filter(item -> selectedList.contains(item.getId())).collect(Collectors.toList());
        }
        return exportList;
    }

    /**
     * 多sheet页导出
     *
     * @param list
     * @param type
     * @return
     */
    public static Workbook exportExcel(List<Map<String, Object>> list, ExcelType type) {
        Workbook workbook = getWorkbook(type, 0);
        for (Map<String, Object> map : list) {
            ExcelExportService service = new ExcelExportService();
            service.createSheetForMap(workbook, (ExportParams) map.get("title"), (List<ExcelExportEntity>) map.get("entity"), (Collection<?>) map.get("data"));
        }
        return workbook;
    }

    private static Workbook getWorkbook(ExcelType type, int size) {
        if (ExcelType.HSSF.equals(type)) {
            return new HSSFWorkbook();
        } else if (size < 100000) {
            return new XSSFWorkbook();
        } else {
            return new SXSSFWorkbook();
        }
    }

    /**
     * 多语言处理
     * @param pojoClass
     * @return
     */
    public static Class convertNameForI18n(Class<?> pojoClass){
        //获取实体类中所有字段
        Field[] fields = pojoClass.getDeclaredFields();
        for (Field field : fields) {
            //判断是否配置了多语言注解
            ExcelI18n excelI18n = field.getAnnotation(ExcelI18n.class);
            if(excelI18n!=null && StringUtils.isNotEmpty(excelI18n.name())){
                //获取多语言的值
                String excelI18nValue = I18nUtil.message(excelI18n.name());
                if(StringUtils.isNotEmpty(excelI18nValue)){
                    ExcelCollection excelCollection = field.getAnnotation(ExcelCollection.class);
                    Excel excel = field.getAnnotation(Excel.class);
                    if(excelCollection!=null){
                        // 获取代理处理器
                        InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelCollection);
                        setMemberValues(invocationHandler,excelI18nValue);
                        ParameterizedType pt = (ParameterizedType) field.getGenericType();
                        Class<?> clz = (Class<?>) pt.getActualTypeArguments()[0];
                        convertNameForI18n(clz);
                    }else if(excel!=null){
                        // 获取代理处理器
                        InvocationHandler invocationHandler = Proxy.getInvocationHandler(excel);
                        setMemberValues(invocationHandler,excelI18nValue);
                    }
                }
            }
        }
        //父类
        Class<?> superclass = pojoClass.getSuperclass();
        if(superclass != Object.class && superclass != null){
            convertNameForI18n(superclass);
        }
        return pojoClass;
    }

    private static void setMemberValues(InvocationHandler invocationHandler,String excelI18nValue){
        // 获取私有 memberValues 属性
        Field f = null;
        try {
            f = invocationHandler.getClass().getDeclaredField("memberValues");
            f.setAccessible(true);
            // 获取实例的属性map
            Map<String, Object> memberValues = (Map<String, Object>) f.get(invocationHandler);
            // 获取属性值
            String excelValue = (String) memberValues.get("name");

            if (StringUtils.isNotBlank(excelValue)) {
                //根据传入的语言标识，重新设置属性值
                memberValues.put("name", excelI18nValue);
            }
        } catch (NoSuchFieldException e) {
            log.error(e.getMessage(), e);
        }catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
    }
}
